<?php

/**
 * @user magein
 * @date 2023/12/7 9:40
 */

namespace magein\think\command;

use magein\think\command\traits\CommandParamParse;

use magein\utils\Variable;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;

class MakeService extends Command
{

    use CommandParamParse;

    protected string $help = '
    1. api使用的数据仓库文件,创建到到配置的目录下
    2. 在config/console.php文件中配置config.service.path参数值
    3. 支持表名称模糊匹配
    
    php think model:service user                      创建service/UserService.php文件
    php think model:service user_order                创建service/UserOrderService.php创建
    php think model:service user/user_order           创建service/user/UserOrderService.php创建
    
    附：仓库目录默认是app/service，可在config/console.php文件中配置config.service.path参数的值
';

    protected function configure()
    {
        // 指令配置
        $this->setName('model:service')
            ->addArgument('name')
            ->addOption('index', 'i', Option::VALUE_OPTIONAL, '选择索引编号')
            ->setDescription('the service command')
            ->setHelp($this->help);
    }

    protected function execute(Input $input, Output $output)
    {
        if (\think\facade\Env::get('app_env') !== 'local') {
            $output->error('只能在开发环境中使用');
            exit();
        }

        $name = $input->getArgument('name');
        $index = $input->getOption('index');

        $result = $this->tableAttrs($name, intval($index));

        if ($result->getCode()) {
            $output->error($result->getMsg());
            return false;
        }

        $table_info = $result->getData();
        $table_name = $table_info['table_name'];
        $attrs = $table_info['attrs'];

        // 保存路径
        $filepath = $this->filepath($table_name, 'service', 'app/service');
        // 文件的命名空间
        $namespace = $this->namespace($filepath);
        $filename = $this->filename($table_name, 'Service');
        $filepath .= Variable::pascal(trim($filename, '/')) . '.php';
        if (is_file($filepath)) {
            $output->error($filepath . '已经存在');
            exit();
        }

        $data = $this->make($attrs, $namespace);

        $template = $this->template($table_name, $data);

        file_put_contents($filepath, $template);
        // 指令输出
        $output->writeln($filepath . '创建成功');
    }

    /**
     * 生成仓库所需要的属性
     * @param $attrs
     * @param string|null $namespace 使用的命名空间
     * @return array
     */
    public function make($attrs, string $namespace = null): array
    {
        $namespace = $namespace ?: 'app\service';

        $use = app()->config->get("console.config.service.extends", 'magein\think\utils\service\BaseService');
        $extends = pathinfo($use, PATHINFO_BASENAME);

        $fields = '';
        $search = '';
        $allow_create = [];
        foreach ($attrs as $attr) {
            $field = $attr['Field'];

            if (in_array($field, ['created_at', 'updated_at', 'deleted_at'])) {
                continue;
            }

            if (empty($fields)) {
                $fields .= "'$field',\n";
            } else {
                $fields .= "        '$field',\n";
            }

            if (in_array($field, ['name', 'phone', 'status', 'mobile', 'sex', 'gender', 'form', 'channel'])
                || str_ends_with($field, '_no')
                || str_ends_with($field, '_id')
                || str_ends_with($field, '_at')
            ) {
                if (empty($search)) {
                    $search .= "'$field',\n";
                } else {
                    $search .= "            '$field',\n";
                }
            }

            if ($field !== 'id') {
                if (empty($allow_create)) {
                    $allow_create[] = "'$field',\n";
                } else {
                    $allow_create[] = "            '$field',\n";
                }
            }

        }
        $fields = trim($fields, "\n");
        $fields .= "\n        'created_at'";
        $fields = trim($fields);

        $search = trim($search, "\n");
        $search = trim($search);

        return compact(
            'namespace',
            'fields',
            'use',
            'extends',
            'search',
            'allow_create',
        );
    }

    /**
     * 模版
     * @param string $table_name
     * @param $params
     * @return string
     */
    public function template(string $table_name, $params = null): string
    {
        extract($params);

        $allow_create = implode("", $allow_create);

        $model = $this->findModelByTableName($table_name, 1);

        $model_name = '';
        $model_namespace = '';
        if ($model) {
            $model_name = pathinfo($model, PATHINFO_FILENAME);
            $model_namespace = pathinfo($model, PATHINFO_DIRNAME) . '/' . $model_name;
            $model_namespace = str_replace('/', '\\', $model_namespace);

            $model_name = $model_name . '::class';
            $model_namespace = 'use ' . $model_namespace . ';';
        }

        $class_name = Variable::pascal($table_name) . 'Service';


        $template = app()->config->get("console.config.service.template", '') ?: dirname(__DIR__) . '/stubs/service.stub';

        if (!is_file($template)) {
            return '';
        }

        $content = file_get_contents($template);

        return preg_replace(
            [
                '/\{\$namespace\}/',
                '/\{\$use\}/',
                '/\{\$model_namespace\}/',
                '/\{\$class_name\}/',
                '/\{\$extends\}/',
                '/\{\$model_name\}/',
                '/\{\$fields\}/',
                '/\{\$search\}/',
                '/\{\$allow_create\}/',
            ],
            [
                $namespace,
                $use,
                $model_namespace,
                $class_name,
                $extends,
                $model_name,
                $fields,
                $search,
                $allow_create,
            ],
            $content
        );
    }
}